﻿using System.Collections.Generic;
using System.IO;
using MiniJson;
using Neatly.Helper;
using Neatly.Module;

namespace Neatly.Load.Manager
{
    public class FileInfoItem
    {
        public string folderName;
        public string fileName;
        public int fileSize;
    }

    public class FileHashItem
    {
        public int BuildTime {get; private set;}
        public int VersionMajor {get; private set;}
        public int VersionMinor {get; private set;}
        public int VersionPatch {get; private set;}
        public Dictionary<string, Dictionary<string, string>> FolderHashMap {get;}
        private Dictionary<string, Dictionary<string, int>> FolderSizeMap {get;}

        public FileHashItem(byte[] dataArray)
        {
            FolderHashMap = new Dictionary<string, Dictionary<string, string>>();
            FolderSizeMap = new Dictionary<string, Dictionary<string, int>>();
            var reader = HashReader.Instance;
            reader.InitBytes(dataArray);
            BuildTime = reader.ReadInt();
            VersionMajor = reader.ReadInt();
            VersionMinor = reader.ReadInt();
            VersionPatch = reader.ReadInt();
            int folderCount = reader.ReadInt();
            for (int i = 0; i < folderCount; i++)
            {
                var folderName = reader.ReadString();
                var fileCount = reader.ReadInt();
                if (!FolderHashMap.TryGetValue(folderName, out var fileHashMap))
                {
                    fileHashMap = new Dictionary<string, string>();
                    FolderHashMap.Add(folderName, fileHashMap);
                }
                if (!FolderSizeMap.TryGetValue(folderName, out var fileSizeMap))
                {
                    fileSizeMap = new Dictionary<string, int>();
                    FolderSizeMap.Add(folderName, fileSizeMap);
                }
                for (int j = 0; j < fileCount; j++)
                {
                    var fileName = reader.ReadString();
                    var md5String = reader.ReadMD5String();
                    var fileSize = reader.ReadInt();
                    fileHashMap.Add(fileName, md5String);
                    fileSizeMap.Add(fileName, fileSize);
                }
            }
        }

        public string GetFileName(string folderName, string fileName)
        {
            return NeatlyHelper.GetFullNameByHash(fileName, FolderHashMap[folderName][fileName]);
        }

        public int GetFileSize(string folderName, string fileName)
        {
            return FolderSizeMap[folderName][fileName];
        }
    }

    public class FileHashManager : Singleton<FileHashManager>
    {
        public FileHashItem SourceHashItem {get; private set;}
        public FileHashItem CurrentHashItem {get; private set;}
        private JsonValue m_HashJson;

        public override void Init()
        {
            base.Init();
#if !UNITY_WEBGL
            if (SourceHashItem != null)
            {
                return;
            }
            byte[] byteArray = FileModule.Instance.ReadFileBytes(NeatlyConfig.FILE_HASH);
            SourceHashItem = new FileHashItem(byteArray);
            CurrentHashItem = SourceHashItem;
#endif
        }

        public void InitCurrentHash(byte[] byteArray)
        {
            CurrentHashItem = new FileHashItem(byteArray);
        }

        public void InitCurrentHash(JsonValue json)
        {
            m_HashJson = json;
        }

        public string GetFileName(string folderName, string fileName)
        {
#if UNITY_WEBGL
            return NeatlyHelper.GetFullNameByHash(fileName, m_HashJson.GetString(fileName));
#else
            return CurrentHashItem.GetFileName(folderName, fileName);
#endif
        }

        public int GetBuildTime()
        {
            return SourceHashItem.BuildTime;
        }

        public List<FileInfoItem> GetAllDifferenceFile()
        {
            List<FileInfoItem> result = new List<FileInfoItem>();
            foreach (var currentFolderKv in CurrentHashItem.FolderHashMap)
            {
                string folderName = currentFolderKv.Key;
                bool hasFolder = SourceHashItem.FolderHashMap.TryGetValue(folderName, out var sourceHashMap);
                foreach (var currentFileKv in currentFolderKv.Value)
                {
                    string fileName = currentFileKv.Key;
                    string currentHash = currentFileKv.Value;
                    if (!hasFolder)
                    {
                        AddFileInfoItemList(result, folderName, fileName, currentHash);
                        continue;
                    }
                    if (!sourceHashMap.TryGetValue(fileName, out var sourceHash) || sourceHash != currentHash)
                    {
                        AddFileInfoItemList(result, folderName, fileName, currentHash);
                    }
                }
            }
            return result;
        }

        private void AddFileInfoItemList(List<FileInfoItem> itemList, string folderName, string sourceFileName, string currentHash)
        {
            var fileName = NeatlyHelper.GetFullNameByHash(sourceFileName, currentHash);
            if (!FileModule.Instance.IsExitsUpdateFile(folderName, fileName))
            {
                var fileInfoItem = new FileInfoItem();
                fileInfoItem.fileName = fileName;
                fileInfoItem.fileSize = CurrentHashItem.GetFileSize(folderName, sourceFileName);
                if (folderName == NeatlyConfig.LUA_PACKAGE_64)
                {
                    folderName = NeatlyConfig.LUA_PACKAGE;
                }
                fileInfoItem.folderName = folderName;
                itemList.Add(fileInfoItem);
            }
        }
    }
}